package org.ssssssss.script.runtime;

import org.ssssssss.script.MagicScriptContext;

import java.util.LinkedHashMap;
import java.util.Map;

public class Variables {

	private final Object[] elements;

	private Variables parent;

	private int[] args;

	private int argLength = -1;

	private static final ThreadLocal<Variables> VARIABLES_THREAD_LOCAL = new ThreadLocal<>();

	public Variables(int size) {
		this.elements = new Object[size];
	}

	public Variables(Object[] elements, int[] args) {
		int len = elements.length;
		this.elements = new Object[len];
		this.args = args;
		this.argLength = args.length;
	}

	public Object getValue(int index){
		Object value = elements[index];
		if(value == null){
			return parent == null ? null : parent.getValue(index);
		}
		return value;
	}

	public void setValue(int index, Object value){
		if(index > -1){
			this.elements[index] = value;
			if(parent != null && argLength > -1){
				for (int i = 0; i < argLength; i++) {
					if(index == this.args[i]){
						return;
					}
				}
				parent.setValue(index,value);
			}
		}
	}

	public Variables copy(Object[] target, int ... args){
		Variables variables = new Variables(this.elements, args);
		variables.parent = this;
		if (args.length > 0) {
			for (int i = 0, len = args.length; i < len; i++) {
				variables.setValue(args[i], target[i]);
			}
		}
		return variables;
	}


	public static void set(Variables variables){
		VARIABLES_THREAD_LOCAL.set(variables);
	}

	public static Variables get(){
		return VARIABLES_THREAD_LOCAL.get();
	}
	public Map<String, Object> getVariables(){
		Map<String, Object> variables = new LinkedHashMap<>();
		if(parent != null){
			variables.putAll(parent.getVariables());
		}
		MagicScriptContext context = MagicScriptContext.get();
		String[] varNames = context.getVarNames();
		for (int i = 0,len = elements.length; i < len; i++) {
			Object value = elements[i];
			if(value != null){
				variables.put(varNames[i], value);
			}
		}
		return variables;
	}

	public static void remove(){
		VARIABLES_THREAD_LOCAL.remove();
	}
}
